/**
 * @copyright Copyright (c) 2025 CSG Digital Grid Technology (Guangdong) Co., Ltd.
 * @author Chen Yongjie
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <CUnit/CUnit.h>
#include "test_unit.h"
#include "unit.h"

// 声明外部变量
extern volatile uint16_t plc_tokenSeed;

/**
 * @brief 测试get_token函数在正常情况下的行为
 */
void test_get_token_normal(void) {
    char token1[16] = {0};
    char token2[16] = {0};
    
    // 记录初始种子值
    uint16_t initial_seed = plc_tokenSeed;
    
    // 第一次调用get_token
    get_token(token1);
    
    // 验证token1是否为当前种子值的字符串形式
    char expected1[16] = {0};
    sprintf(expected1, "%d", initial_seed);
    CU_ASSERT_STRING_EQUAL(token1, expected1);
    
    // 验证种子值是否增加
    CU_ASSERT_EQUAL(plc_tokenSeed, initial_seed + 1);
    
    // 第二次调用get_token
    get_token(token2);
    
    // 验证token2是否为增加后的种子值
    char expected2[16] = {0};
    sprintf(expected2, "%d", initial_seed + 1);
    CU_ASSERT_STRING_EQUAL(token2, expected2);
    
    // 验证两个token是否不同
    CU_ASSERT_STRING_NOT_EQUAL(token1, token2);
}

/**
 * @brief 测试get_token函数在种子值接近最大值时的行为
 */
void test_get_token_max_value(void) {
    char token[16] = {0};
    
    // 设置种子值为最大值
    plc_tokenSeed = 65535;
    
    // 调用get_token
    get_token(token);
    
    // 验证token是否为"65535"
    CU_ASSERT_STRING_EQUAL(token, "65535");
    
    // 验证种子值是否重置为0
    CU_ASSERT_EQUAL(plc_tokenSeed, 0);
    
    // 再次调用get_token
    char next_token[16] = {0};
    get_token(next_token);
    
    // 验证新token是否为"0"
    CU_ASSERT_STRING_EQUAL(next_token, "0");
    
    // 验证种子值是否为1
    CU_ASSERT_EQUAL(plc_tokenSeed, 1);
}

/**
 * @brief 测试get_token函数对空指针的处理
 */
void test_get_token_null_pointer(void) {
    // 记录初始种子值
    uint16_t initial_seed = plc_tokenSeed;
    
    // 使用NULL指针调用函数
    get_token(NULL);
    
    // 验证种子值是否仍然增加
    CU_ASSERT_EQUAL(plc_tokenSeed, initial_seed + 1);
}

/**
 * @brief 测试itobcd函数在正常范围内的转换
 */
void test_itobcd_normal_range(void) {
    // 测试边界值0
    uint8_t result = itobcd(0);
    CU_ASSERT_EQUAL(result, 0x00);
    
    // 测试个位数9
    result = itobcd(9);
    CU_ASSERT_EQUAL(result, 0x09);
    
    // 测试10
    result = itobcd(10);
    CU_ASSERT_EQUAL(result, 0x10);
    
    // 测试常规双位数23
    result = itobcd(23);
    CU_ASSERT_EQUAL(result, 0x23);
    
    // 测试边界值99
    result = itobcd(99);
    CU_ASSERT_EQUAL(result, 0x99);
}

/**
 * @brief 测试itobcd函数对特殊值的处理
 */
void test_itobcd_special_values(void) {
    // 测试超出范围的值100
    uint8_t result = itobcd(100);
    // 由于是8位BCD，结果应该是0x00
    CU_ASSERT_EQUAL(result, 0x00);
    
    // 测试较大的值255
    result = itobcd(255);
    // 验证结果是否符合预期的截断行为
    CU_ASSERT_EQUAL(result, ((25 << 4) | (5 & 0x0f)));
}

/**
 * @brief 测试get_system_time_us函数的功能
 */
void test_get_system_time_us_normal(void) {
    // 获取第一个时间戳
    uint64_t time1 = get_system_time_us();
    
    // 延时一小段时间
    usleep(1000); // 延时1毫秒
    
    // 获取第二个时间戳
    uint64_t time2 = get_system_time_us();
    
    // 验证第二个时间戳大于第一个时间戳
    CU_ASSERT_TRUE(time2 > time1);
    
    // 验证时间差大约为1毫秒（1000微秒）
    uint64_t diff = time2 - time1;
    // 允许有一定误差，这里设置误差范围为±500微秒
    CU_ASSERT_TRUE(diff >= 500 && diff <= 1500);
}

/**
 * @brief 测试get_system_time_absoffset函数在正常情况下的行为
 */
void test_get_system_time_absoffset_normal(void) {
    // 测试用例1：current > last
    uint64_t current1 = 1000000;
    uint64_t last1 = 500000;
    uint64_t result1 = get_system_time_absoffset(current1, last1);
    CU_ASSERT_EQUAL(result1, 500000);
    
    // 测试用例2：current = last
    uint64_t current2 = 1000000;
    uint64_t last2 = 1000000;
    uint64_t result2 = get_system_time_absoffset(current2, last2);
    CU_ASSERT_EQUAL(result2, 0);
    
    // 测试用例3：较大数值
    uint64_t current3 = 0xFFFFFFFF00000000ULL;
    uint64_t last3 = 0xFFFFFFFE00000000ULL;
    uint64_t result3 = get_system_time_absoffset(current3, last3);
    CU_ASSERT_EQUAL(result3, 0x100000000ULL);
}

/**
 * @brief 测试get_system_time_absoffset函数在时间戳溢出情况下的行为
 */
void test_get_system_time_absoffset_overflow(void) {
    // 测试时间戳溢出的情况
    uint64_t current = 1000;
    uint64_t last = 0xFFFFFFFFFFFFFFFEULL; // 接近最大值
    uint64_t result = get_system_time_absoffset(current, last);
    
    // 预期结果应该是：(0xFFFFFFFFFFFFFFFF - last) + current
    uint64_t expected = (0xFFFFFFFFFFFFFFFFULL - last) + current;
    CU_ASSERT_EQUAL(result, expected);
    
    // 测试边界情况
    current = 0;
    last = 0xFFFFFFFFFFFFFFFFULL;
    result = get_system_time_absoffset(current, last);
    CU_ASSERT_EQUAL(result, 1);
}

/**
 * @brief 测试AtoH函数在正常情况下的行为
 */
void test_AtoH_normal(void) {
    char *test_str = "48656C6C6F"; // "Hello" in hex
    uint8_t output[16] = {0};
    
    // 调用被测试函数
    int result = AtoH(test_str, output);
    
    // 验证返回值（应该是输出字节数）
    CU_ASSERT_EQUAL(result, 5);
    
    // 验证转换结果
    uint8_t expected[] = {0x48, 0x65, 0x6C, 0x6C, 0x6F};
    for(int i = 0; i < 5; i++) {
        CU_ASSERT_EQUAL(output[i], expected[i]);
    }
    
    // 测试小写十六进制字符
    char *test_str2 = "6162636465"; // "abcde" in hex
    memset(output, 0, sizeof(output));
    result = AtoH(test_str2, output);
    
    CU_ASSERT_EQUAL(result, 5);
    uint8_t expected2[] = {0x61, 0x62, 0x63, 0x64, 0x65};
    for(int i = 0; i < 5; i++) {
        CU_ASSERT_EQUAL(output[i], expected2[i]);
    }
}

/**
 * @brief 测试AtoH函数处理空指针的情况
 */
void test_AtoH_null_pointer(void) {
    uint8_t output[16] = {0};
    
    // 测试输入字符串为NULL的情况
    int result = AtoH(NULL, output);
    CU_ASSERT_EQUAL(result, 0);
    
    // 测试输出缓冲区为NULL的情况
    char *test_str = "48656C6C6F";
    result = AtoH(test_str, NULL);
    CU_ASSERT_EQUAL(result, 0);
}

/**
 * @brief 测试AtoH函数处理空字符串的情况
 */
void test_AtoH_empty_string(void) {
    char *test_str = "";
    uint8_t output[16] = {0};
    
    int result = AtoH(test_str, output);
    CU_ASSERT_EQUAL(result, 0);
}

/**
 * @brief 测试AtoH函数处理奇数长度字符串的情况
 */
void test_AtoH_odd_length(void) {
    char *test_str = "48656"; // 奇数长度的十六进制字符串
    uint8_t output[16] = {0};
    
    int result = AtoH(test_str, output);
    
    // 验证返回值（应该是3，两个完整字节加一个半字节）
    CU_ASSERT_EQUAL(result, 3);
    
    // 验证前两个完整字节
    CU_ASSERT_EQUAL(output[0], 0x48);
    CU_ASSERT_EQUAL(output[1], 0x65);
    
    // 验证最后一个半字节
    CU_ASSERT_EQUAL(output[2], 0x06);
}

/**
 * @brief 测试mqtt_get_time函数的正常行为
 */
void test_mqtt_get_time_normal(void) {
    char timestamp[32] = {0};
    
    // 调用被测试函数
    mqtt_get_time(timestamp);
    
    // 验证时间戳格式
    // 格式应该是: "YYYY-MM-DDThh:mm:ss"
    CU_ASSERT_EQUAL(strlen(timestamp), 19);
    CU_ASSERT_EQUAL(timestamp[4], '-');
    CU_ASSERT_EQUAL(timestamp[7], '-');
    CU_ASSERT_EQUAL(timestamp[10], 'T');
    CU_ASSERT_EQUAL(timestamp[13], ':');
    CU_ASSERT_EQUAL(timestamp[16], ':');
    
    // 验证年份是否在合理范围（2021-2100）
    char year[5] = {0};
    strncpy(year, timestamp, 4);
    int year_num = atoi(year);
    CU_ASSERT_TRUE(year_num >= 2021 && year_num <= 2100);
    
    // 验证月份是否在合理范围（01-12）
    char month[3] = {0};
    strncpy(month, timestamp + 5, 2);
    int month_num = atoi(month);
    CU_ASSERT_TRUE(month_num >= 1 && month_num <= 12);
    
    // 验证日期是否在合理范围（01-31）
    char day[3] = {0};
    strncpy(day, timestamp + 8, 2);
    int day_num = atoi(day);
    CU_ASSERT_TRUE(day_num >= 1 && day_num <= 31);
    
    // 验证小时是否在合理范围（00-23）
    char hour[3] = {0};
    strncpy(hour, timestamp + 11, 2);
    int hour_num = atoi(hour);
    CU_ASSERT_TRUE(hour_num >= 0 && hour_num <= 23);
    
    // 验证分钟是否在合理范围（00-59）
    char minute[3] = {0};
    strncpy(minute, timestamp + 14, 2);
    int minute_num = atoi(minute);
    CU_ASSERT_TRUE(minute_num >= 0 && minute_num <= 59);
    
    // 验证秒数是否在合理范围（00-59）
    char second[3] = {0};
    strncpy(second, timestamp + 17, 2);
    int second_num = atoi(second);
    CU_ASSERT_TRUE(second_num >= 0 && second_num <= 59);
}

/**
 * @brief 测试mqtt_get_time函数对空指针的处理
 */
void test_mqtt_get_time_null_pointer(void) {
    // 使用NULL指针调用函数
    mqtt_get_time(NULL);
    
    // 如果程序能继续执行，说明函数正确处理了NULL指针
    CU_PASS("Function handled NULL pointer gracefully");
}

/**
 * @brief 测试delay_ms函数的正常行为
 */
void test_delay_ms_normal(void) {
    // 获取开始时间
    struct timeval start, end;
    gettimeofday(&start, NULL);
    
    // 延时1000毫秒（1秒）
    delay_ms(1000);
    
    // 获取结束时间
    gettimeofday(&end, NULL);
    
    // 计算实际延时（毫秒）
    long elapsed = (end.tv_sec - start.tv_sec) * 1000 + 
                  (end.tv_usec - start.tv_usec) / 1000;
    
    // 验证延时是否在预期范围内（允许±100ms的误差）
    CU_ASSERT_TRUE(elapsed >= 900 && elapsed <= 1100);
}

/**
 * @brief 测试delay_ms函数在不同延时值下的行为
 */
void test_delay_ms_various_delays(void) {
    // 测试延时值数组（单位：毫秒）
    unsigned long delays[] = {10, 50, 100, 500};
    int num_tests = sizeof(delays) / sizeof(delays[0]);
    
    for (int i = 0; i < num_tests; i++) {
        struct timeval start, end;
        gettimeofday(&start, NULL);
        
        delay_ms(delays[i]);
        
        gettimeofday(&end, NULL);
        
        // 计算实际延时（毫秒）
        long elapsed = (end.tv_sec - start.tv_sec) * 1000 + 
                      (end.tv_usec - start.tv_usec) / 1000;
        
        // 验证延时是否在预期范围内（允许±20%的误差）
        long min_expected = delays[i] * 0.8;
        long max_expected = delays[i] * 1.2;
        CU_ASSERT_TRUE(elapsed >= min_expected && elapsed <= max_expected);
    }
}

void test_get_current_time_global_normal(void) {
    char timestamp[32] = {0};
    
    // 调用被测试函数
    int result = get_current_time_global(timestamp);
    
    // 验证返回值
    CU_ASSERT_EQUAL(result, 0);
    
    // 验证时间戳格式和长度
    // 格式应该是: "YYYY-MM-DDThh:mm:ss.000+0800"
    CU_ASSERT_EQUAL(strlen(timestamp), 28);
    CU_ASSERT_EQUAL(timestamp[4], '-');
    CU_ASSERT_EQUAL(timestamp[7], '-');
    CU_ASSERT_EQUAL(timestamp[10], 'T');
    CU_ASSERT_EQUAL(timestamp[13], ':');
    CU_ASSERT_EQUAL(timestamp[16], ':');
    CU_ASSERT_EQUAL(timestamp[19], '.');
    CU_ASSERT_STRING_EQUAL(timestamp + 23, "+0800");
    
    // 验证年份是否在合理范围（2021-2100）
    char year[5] = {0};
    strncpy(year, timestamp, 4);
    int year_num = atoi(year);
    CU_ASSERT_TRUE(year_num >= 2021 && year_num <= 2100);
    
    // 验证月份是否在合理范围（01-12）
    char month[3] = {0};
    strncpy(month, timestamp + 5, 2);
    int month_num = atoi(month);
    CU_ASSERT_TRUE(month_num >= 1 && month_num <= 12);
    
    // 验证日期是否在合理范围（01-31）
    char day[3] = {0};
    strncpy(day, timestamp + 8, 2);
    int day_num = atoi(day);
    CU_ASSERT_TRUE(day_num >= 1 && day_num <= 31);
    
    // 验证小时是否在合理范围（00-23）
    char hour[3] = {0};
    strncpy(hour, timestamp + 11, 2);
    int hour_num = atoi(hour);
    CU_ASSERT_TRUE(hour_num >= 0 && hour_num <= 23);
    
    // 验证分钟是否在合理范围（00-59）
    char minute[3] = {0};
    strncpy(minute, timestamp + 14, 2);
    int minute_num = atoi(minute);
    CU_ASSERT_TRUE(minute_num >= 0 && minute_num <= 59);
    
    // 验证秒数是否在合理范围（00-59）
    char second[3] = {0};
    strncpy(second, timestamp + 17, 2);
    int second_num = atoi(second);
    CU_ASSERT_TRUE(second_num >= 0 && second_num <= 59);
    
    // 验证毫秒部分是否为"000"
    char ms[4] = {0};
    strncpy(ms, timestamp + 20, 3);
    CU_ASSERT_STRING_EQUAL(ms, "000");
}

void test_get_current_time_global_null_pointer(void) {
    // 使用NULL指针调用函数
    int result = get_current_time_global(NULL);
    
    // 验证返回值是否为0（函数应该优雅处理NULL指针）
    CU_ASSERT_EQUAL(result, 0);
}

/**
 * @brief 测试 AtoH 函数对非法字符的处理
 * 
 * 测试步骤：
 * 1. 准备包含非法字符的输入字符串
 * 2. 调用 AtoH 函数
 * 3. 验证处理结果
 * 
 * 预期结果：
 * 1. 函数应该能正确处理非法字符
 * 2. 返回值应该反映实际转换的字节数
 * 3. 不应发生段错误
 */
void test_AtoH_invalid_chars(void) {
    uint8_t output[16] = {0};
    
    // 测试非十六进制字符
    char *test_str1 = "48GH6C6C6F";
    int result = AtoH(test_str1, output);
    CU_ASSERT_EQUAL(result, 5);
    
    // 测试特殊字符
    char *test_str2 = "48!@#C6C6F";
    result = AtoH(test_str2, output);
    CU_ASSERT_EQUAL(result, 5);
}

/**
 * @brief 测试 get_token 函数在高频调用时的行为
 * 
 * 测试步骤：
 * 1. 快速连续调用函数多次
 * 2. 验证生成的token序列
 * 3. 检查种子值变化
 * 
 * 预期结果：
 * 1. 每个token应该唯一
 * 2. 种子值应正确递增
 * 3. 不应出现竞态条件
 */
void test_get_token_rapid_calls(void) {
    char tokens[1000][16];
    uint16_t initial_seed = plc_tokenSeed;
    
    // 快速连续获取1000个token
    for(int i = 0; i < 1000; i++) {
        get_token(tokens[i]);
    }
    
    // 验证所有token都是唯一的
    for(int i = 0; i < 999; i++) {
        for(int j = i + 1; j < 1000; j++) {
            CU_ASSERT_STRING_NOT_EQUAL(tokens[i], tokens[j]);
        }
    }
    
    // 验证最终种子值
    CU_ASSERT_EQUAL(plc_tokenSeed, (initial_seed + 1000) % 65536);
}

/**
 * @brief 测试 itobcd 函数在连续值序列上的行为
 * 
 * 测试步骤：
 * 1. 测试连续的数值范围
 * 2. 验证BCD转换结果
 * 
 * 预期结果：
 * 1. 所有转换结果应符合BCD格式
 * 2. 结果应在预期范围内
 */
void test_itobcd_sequence(void) {
    // 测试0-99的所有数字
    for(uint8_t i = 0; i < 100; i++) {
        uint8_t result = itobcd(i);
        uint8_t expected = ((i / 10) << 4) | (i % 10);
        CU_ASSERT_EQUAL(result, expected);
    }
}

/**
 * @brief 测试 delay_ms 函数在极短延时情况下的行为
 * 
 * 测试步骤：
 * 1. 使用极短的延时值
 * 2. 测量实际延时时间
 * 
 * 预期结果：
 * 1. 函数应能处理极短延时
 * 2. 实际延时应接近预期值
 */
void test_delay_ms_short_delays(void) {
    struct timeval start, end;
    unsigned long delays[] = {1, 2, 5};
    
    for(int i = 0; i < sizeof(delays)/sizeof(delays[0]); i++) {
        gettimeofday(&start, NULL);
        delay_ms(delays[i]);
        gettimeofday(&end, NULL);
        
        long elapsed = (end.tv_sec - start.tv_sec) * 1000000 + 
                      (end.tv_usec - start.tv_usec);
        
        // 验证延时误差不超过1ms
        CU_ASSERT_TRUE(abs(elapsed - delays[i]*1000) < 1000);
    }
}

/**
 * @brief 测试 mqtt_get_time 函数在时区变更情况下的行为
 * 
 * 测试步骤：
 * 1. 保存原始时区
 * 2. 修改系统时区
 * 3. 获取时间戳
 * 4. 恢复原始时区
 * 
 * 预期结果：
 * 1. 时间戳格式应保持一致
 * 2. 时间值应反映正确时区
 */
void test_mqtt_get_time_timezone_change(void) {
    char timestamp1[32] = {0};
    char timestamp2[32] = {0};
    
    // 保存当前时区
    char *original_tz = getenv("TZ");
    
    // 设置为UTC时区
    setenv("TZ", "UTC", 1);
    tzset();
    mqtt_get_time(timestamp1);
    
    // 设置为亚洲时区
    setenv("TZ", "Asia/Shanghai", 1);
    tzset();
    mqtt_get_time(timestamp2);
    
    // 恢复原始时区
    if (original_tz) {
        setenv("TZ", original_tz, 1);
    } else {
        unsetenv("TZ");
    }
    tzset();
    
    // 验证时间戳格式
    CU_ASSERT_EQUAL(strlen(timestamp1), 19);
    CU_ASSERT_EQUAL(strlen(timestamp2), 19);
    
    // 验证两个时间戳的时差应约为8小时
    int hour1, hour2;
    sscanf(timestamp1 + 11, "%d", &hour1);
    sscanf(timestamp2 + 11, "%d", &hour2);
    
    int hour_diff = (hour2 - hour1 + 24) % 24;
    CU_ASSERT_TRUE(hour_diff == 8 || hour_diff == 7 || hour_diff == 9);
}